<?php
declare(strict_types=1);

namespace Dreamcat\ApiDoc\Popo;

use Dreamcat\ApiDoc\Error\PopoException;

/**
 * API接口描述
 * @author vijay
 */
class ApiDefinition
{
    /** @var string 请求地址 */
    private string $uri;
    /** @var string 接口名称 */
    private string $name;
    /** @var string 接口描述 */
    private string $desc = "";
    /** @var string 接口分类 */
    private string $apiTag;
    /** @var string 请求方法 */
    private string $method;
    /**
     * @var BodyDefinition[] get参数定义
     * @note 元素类型只能是 int/float/enum/string/bool/array
     * @note array时，元素类型依然只能是上面的情况
     */
    private array $getDefinition = [];
    /** @var BodyDefinition[] 占位符定义 */
    private array $pathVariableDefinition = [];
    /** @var BodyDefinition[] 报头 */
    private array $headers = [];
    /** @var BodyDefinition[] cookie */
    private array $cookies = [];
    /** @var ?BodyDefinition 请求消息体定义 */
    private ?BodyDefinition $bodyDefinition = null;
    /** @var ?BodyDefinition 响应消息体定义 */
    private ?BodyDefinition $responseDefinition = null;

    /**
     * @return string 请求地址
     */
    public function getUri(): string
    {
        return $this->uri;
    }

    /**
     * @param string $uri 请求地址
     * @return static 对象本身
     */
    public function setUri(string $uri): ApiDefinition
    {
        $this->uri = $uri;
        return $this;
    }

    /**
     * @return string 接口名称
     */
    public function getName(): string
    {
        return $this->name;
    }

    /**
     * @param string $name 接口名称
     * @return static 对象本身
     */
    public function setName(string $name): ApiDefinition
    {
        $this->name = $name;
        return $this;
    }

    /**
     * @return string 接口描述
     */
    public function getDesc(): string
    {
        return $this->desc;
    }

    /**
     * @param string $desc 接口描述
     * @return ApiDefinition
     */
    public function setDesc(string $desc): ApiDefinition
    {
        $this->desc = $desc;
        return $this;
    }

    /**
     * @return string 请求方法
     */
    public function getMethod(): string
    {
        return $this->method;
    }

    /**
     * @param string $method 请求方法
     * @return static 对象本身
     */
    public function setMethod(string $method): ApiDefinition
    {
        $this->method = $method;
        return $this;
    }

    /**
     * @return string 接口分类
     */
    public function getApiTag(): string
    {
        return $this->apiTag ?? "";
    }

    /**
     * @param string $apiTag 接口分类
     * @return static 对象本身
     */
    public function setApiTag(string $apiTag): ApiDefinition
    {
        $this->apiTag = $apiTag;
        return $this;
    }

    /**
     * @return BodyDefinition[] get参数定义
     */
    public function getGetDefinitionList(): array
    {
        return $this->getDefinition;
    }

    /**
     * 获取指定的get参数
     * @param string $key 字段名
     * @return BodyDefinition|null 定义
     */
    public function getGetDefine(string $key): ?BodyDefinition
    {
        return $this->getDefinition[$key] ?? null;
    }

    /**
     * 添加对象字段定义
     * @param BodyDefinition $definition 对象字段定义。字段名必须填写
     * @return static 对象本身
     */
    public function addGetDefinition(BodyDefinition $definition): ApiDefinition
    {
        $field = $definition->getField();
        if (is_null($field) || !strlen($field)) {
            throw new PopoException("Get 对象属性必须定义字段名", PopoException::GET_FIELD_CANT_EMPTY);
        }
        $this->getDefinition[$field] = $definition;
        return $this;
    }

    /**
     * @return BodyDefinition[] 占位符定义
     */
    public function getPathVariableDefinitionList(): array
    {
        return $this->pathVariableDefinition;
    }

    /**
     * 获取指定的占位符定义
     * @param string $key 字段名
     * @return BodyDefinition|null 定义
     */
    public function getPathVariableDefinition(string $key): ?BodyDefinition
    {
        return $this->pathVariableDefinition[$key] ?? null;
    }

    /**
     * 添加占位符定义
     * @param BodyDefinition $definition 对象字段定义。字段名必须填写
     * @return static 对象本身
     */
    public function addPathVariableDefinition(BodyDefinition $definition): ApiDefinition
    {
        $field = $definition->getField();
        if (is_null($field) || !strlen($field)) {
            throw new PopoException("Path Variable 对象属性必须定义字段名", PopoException::PATH_FIELD_CANT_EMPTY);
        }
        $this->pathVariableDefinition[$field] = $definition;
        return $this;
    }

    /**
     * @return BodyDefinition[] 报头
     */
    public function getHeaders(): array
    {
        return $this->headers;
    }

    /**
     * 添加报头定义
     * @param BodyDefinition $definition 对象字段定义。字段名必须填写
     * @return static 对象本身
     */
    public function addHeaderDefinition(BodyDefinition $definition): ApiDefinition
    {
        $field = $definition->getField();
        if (is_null($field) || !strlen($field)) {
            throw new PopoException("Header 对象属性必须定义字段名", PopoException::HEADER_FIELD_CANT_EMPTY);
        }
        $this->headers[$field] = $definition;
        return $this;
    }

    /**
     * @return BodyDefinition[] cookie
     */
    public function getCookies(): array
    {
        return $this->cookies;
    }

    /**
     * 添加cookie定义
     * @param BodyDefinition $definition 对象字段定义。字段名必须填写
     * @return static 对象本身
     */
    public function addCookieDefinition(BodyDefinition $definition): ApiDefinition
    {
        $field = $definition->getField();
        if (is_null($field) || !strlen($field)) {
            throw new PopoException("Cookie 对象属性必须定义字段名", PopoException::COOKIE_FIELD_CANT_EMPTY);
        }
        $this->cookies[$field] = $definition;
        return $this;
    }

    /**
     * @return ?BodyDefinition 请求消息体定义
     */
    public function getBodyDefinition(): ?BodyDefinition
    {
        return $this->bodyDefinition;
    }

    /**
     * @param ?BodyDefinition $bodyDefinition 请求消息体定义
     * @return static 对象本身
     */
    public function setBodyDefinition(?BodyDefinition $bodyDefinition): ApiDefinition
    {
        $this->bodyDefinition = $bodyDefinition;
        return $this;
    }

    /**
     * @return ?BodyDefinition 响应消息体定义
     */
    public function getResponseDefinition(): ?BodyDefinition
    {
        return $this->responseDefinition;
    }

    /**
     * @param ?BodyDefinition $responseDefinition 响应消息体定义
     * @return static 对象本身
     */
    public function setResponseDefinition(?BodyDefinition $responseDefinition): ApiDefinition
    {
        $this->responseDefinition = $responseDefinition;
        return $this;
    }
}

# end of file
